package actions;

import static client.ClientApplication.clientBinding;

import java.awt.Cursor;
import java.awt.event.ActionEvent;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.SocketAddress;
import java.util.StringTokenizer;

import javax.swing.JOptionPane;

import parameters.RLM_Parameters;
import client.ClientApplication;
import client.ClientBindObject;
import client.ClientSocketConnection;
import client_gui.ClientWindow;
import client_gui_chat.ChatDialog;
import client_tree.User;

public class SendMessageAction extends RLMAbstractAction {

	private static final int SOCKET_TIMEOUT	= 10000;
	
	public SendMessageAction(ClientWindow owner) {
		setActionOwner(owner);
//		putValue(ACCELERATOR_KEY, KeyStroke.getKeyStroke(KeyEvent.VK_F8, 0));
		putValue(SMALL_ICON, loadIcon("images/send_msg.png"));
		putValue(NAME, "Send Message");
		putValue(SHORT_DESCRIPTION, "Slanje poruke");
	}
	
	private User user = null;
	boolean invokedExternal = false;
	
	public void setUserExternal(User user) {
		this.user = user;
		this.invokedExternal = true;
	}
	
	public void actionPerformed(ActionEvent e) {
		
		getActionOwner().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
		
		try {
			ClientApplication.bindingSemaphore.acquire();
		}
		catch (InterruptedException e1) {
			e1.printStackTrace();
		}
		
		try {
			if ( !invokedExternal )
				user = getActionOwner().getSelectedUser();
			
			if ( clientBinding.get(user.getUsername()) != null &&
				 clientBinding.get(user.getUsername()).isDialogOpen() == true &&
				 clientBinding.get(user.getUsername()).isConnectionActive() == true ) {
					ClientApplication.bindingSemaphore.release();
					getActionOwner().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
					return;
			}
						
			if ( clientBinding.get(user.getUsername()) == null || clientBinding.get(user.getUsername()).isConnectionActive() == false ) {
//				Socket socket = new Socket(user.getIp_address(), user.getPort());
				Socket socket = new Socket();
				
				boolean connected = false;
				
				if ( RLM_Parameters.isLan() ) {
					try {
						SocketAddress addressToConnect = new InetSocketAddress(user.getLocalAddress(), user.getPort());
//						socket = new Socket(user.getLocalAddress(), user.getPort());
						socket.connect(addressToConnect, SOCKET_TIMEOUT);
						connected = true;
					}
					catch (Exception ex) {
						connected = false;
					}
				}
				else {	
					/*
					 * Ako korisnici imaju istu public IP adresu, znaci da se nalaze iza istog rutera u
					 * okviru lokalne mreze.
					 */
					if ( getActionOwner().getApplicaton().getClientUser().getPublicIP().equals(user.getIp_address()) ) {
						// pokusaj konekcije u lokalnoj mrezi
						try {
							SocketAddress addressToConnect = new InetSocketAddress(user.getLocalAddress(), user.getPort());
//							socket = new Socket(user.getLocalAddress(), user.getPort());
							socket.connect(addressToConnect, SOCKET_TIMEOUT);
							connected = true;
						}
						catch (Exception ex) {
							connected = false;
						}
					}
					else {
						if ( !connected ) {
							try {
								SocketAddress addressToConnect = new InetSocketAddress(user.getIp_address(), user.getPort());
//								socket = new Socket(user.getIp_address(), user.getPort());
								socket.connect(addressToConnect, SOCKET_TIMEOUT);
								connected = true;
							}
							catch (Exception ex) {
								connected = false;
							}
						}
					}
				}
				
				if ( !connected ) {
					JOptionPane.showMessageDialog(getActionOwner(), "The remote host is unreachable !", "Connection error", JOptionPane.ERROR_MESSAGE);
					ClientApplication.bindingSemaphore.release();
					getActionOwner().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
					return;
				}
				
				ClientSocketConnection connection = new ClientSocketConnection(getActionOwner().getApplicaton(), socket, P2P_CONNECTION);
				
				connection.setMessage(SEND_MSG_CMD, "CLIENT_INIT " + getActionOwner().getApplicaton().getClientUser().getUsername());
				
				String ID_string = connection.buffers[SEND_MSG_CMD].read();
				
				if ( !ID_string.startsWith("CLIENT_ID") ) {
					connection.quitConnection();
					ClientApplication.bindingSemaphore.release();
					getActionOwner().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
					return;
				}
				
				StringTokenizer tokens = new StringTokenizer(ID_string);
				tokens.nextToken();
				
				long ID = Long.parseLong(tokens.nextToken());

				ClientSocketConnection serverConnection = null;
				ClientBindObject clientBindObject = null;
				
				if (clientBinding.get(user.getUsername()) != null) {
					serverConnection = clientBinding.get(user.getUsername()).getConnection();
				}
 
				if (serverConnection != null) { 
					long serverID = serverConnection.getConnectionID();
					if (ID > serverID) {
						clientBindObject = new ClientBindObject(user, serverConnection);
						clientBinding.put(user.getUsername(), clientBindObject);
						connection.quitConnection();
					}
					else {
						clientBindObject = new ClientBindObject(user, connection);
						clientBinding.put(user.getUsername(), clientBindObject);
						serverConnection.quitConnection();
					}
				}
				else {
					connection.setConnectionID(ID);
					if (clientBinding.get(user.getUsername()) == null) {
						clientBindObject = new ClientBindObject(user, connection);
						clientBinding.put(user.getUsername(), clientBindObject);
					}
					else {
						clientBinding.get(user.getUsername()).setConnection(connection);
					}
				}
			}
			
			ClientBindObject cbo = clientBinding.get(user.getUsername());
			
			ChatDialog chatDialog = null;

			if (cbo.isDialogOpen() == false) {
				chatDialog = new ChatDialog(getActionOwner(), user);
			}
			else {
				chatDialog = cbo.getDialog();
			}

			cbo.setChatDialog(chatDialog);
			cbo.setChatDialogConnection(cbo.getConnection());
			chatDialog.setVisible(true);
			
			ClientApplication.bindingSemaphore.release();
		}
		catch (Exception ex) {
			ClientApplication.bindingSemaphore.release();
			ex.printStackTrace();
		}
		
		invokedExternal = false;
		
		getActionOwner().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
	}

}
